﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageServer.utilities;

namespace MessageServer.channels
{
    /**
     * The Context in which the handlers will operate on.
     * */
    public interface HandlerContext : IDisposable
    {
        ChannelPipeline belongsTo { get; }  //Attribute to access the pipeline for this context
        Handler handler { get; }            //The handler for this context
        Object data { get; set; }           //data for this context

        bool canStreamUp();                 //is for streaming up
        bool canStreamDown();               //is for streaming down

        void streamUp(ChannelEvent e);      //stream up to the next handler
        void streamDown(ChannelEvent e);    //stream down to the next handler
    }

    public enum HandlerState { done, gonext, errorcontinue, error }

    /**
     * The Handler interface to be implemented to be able to 
     * handle events in the pipeline. Do not use this directly
     * use the streamuphandler and streamdownhandlers.
     * */
    public interface Handler : IDisposable
    {
        //a representative key to get this handler
        String handle { get; }
    }

    /**
     * Interface to implement to handle streamup messages.
     * */
    public interface UpStreamHandler : Handler
    {
        //implement the functionality to handler when messages are streamed up
        HandlerState handleUpStream(HandlerContext ctx, ChannelEvent evt);
    }

    /**
     * Interface to implement to handle streamdown messages.
     * */
    public interface DownStreamHandler : Handler
    {
        //implement the functionality to handle when messages are streamed down
        HandlerState handleDownStream(HandlerContext ctx, ChannelEvent evt);
    }

    /**
     * A default implementation the HandlerContext that can be used in conjunction
     * with the DefaultPipeline implementation
     * */
    public class DefaultHandlerContext : HandlerContext
    {
        Pipeline<DefaultHandlerContext> _pipe;     //Pipeline to which this context belongs
        DefaultChannelPipeline _belongsTo;  //the ChannelPipeline to which this belongs
        Handler _handler;                   //The handler of this context
        Object _data;                       //the data for this context
        bool _upstream;                     //can streamup
        bool _downstream;                   //can stream down

        [NextT]
        DefaultHandlerContext _next;        //expect the pipe to populate the next here
            
        [PrevT]
        DefaultHandlerContext _previous;    //expect the pipe to populate the previous here

        /**
         * The context is constructed for the pipe give, the channel pipeline given
         * and the handler given.
         * */
        public DefaultHandlerContext(Pipeline<DefaultHandlerContext> pipe, 
            DefaultChannelPipeline belongsTo, Handler handle)
        {
            _belongsTo = belongsTo;
            _pipe = pipe;
            _handler = handle;
            _upstream = (handle is UpStreamHandler);
            _downstream = (handle is DownStreamHandler);
            _next = null;
            _previous = null;
        }

        public ChannelPipeline belongsTo { get { return _belongsTo; } } //ChannelPipeline of this context
        public Handler handler { get { return _handler;} }              //Handler of this context
        public Object data { get { return _data; } set { _data = value; } } //data of this context

        public bool canStreamUp() { return _upstream; }                     //can streamup?
        public bool canStreamDown() { return _downstream; }                 //can streamdown?

        public DefaultHandlerContext next { get { return _next; } }         //the next context
        public DefaultHandlerContext previous { get { return _previous; } } //the previous context

        //stream up to the next handler context
        public void streamUp(ChannelEvent e)
        {
            //the pipeline takes care of this
            //if (_next != null)
            {
                _belongsTo.streamup(_next, e);
            }
        }

        //stream down to the previous handler context
        public void streamDown(ChannelEvent e)
        {
            //let the pipeline handle this.
            //if (_previous != null)
            //{
                _belongsTo.streamdown(_previous, e);
            //}
            //else
            //{
            //    _belongsTo.sink.sinkEvent(_belongsTo, e);
            //}
        }

        public void Dispose()
        {
        }
    }
}
